From: Florian Müllner Date: Thu, 19 Jul 2018 13:54:33 +0000 (+0200) Subject: screenshot: Adopt GIO's async pattern X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~929^2~4^2~26 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=da537cda43;p=gnome-shell.git screenshot: Adopt GIO's async pattern A custom callback type is more convenient, but only as long as no other callback type is required. We are about to add functionality that does not return the filename to a screenshot saved on disk, so prepare for that by moving to GIO's generic async callback pattern. https://gitlab.gnome.org/GNOME/gnome-shell/issues/286 --- diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js index 6e99568a3..5f9ab1933 100644 --- a/js/ui/screenshot.js +++ b/js/ui/screenshot.js @@ -110,7 +110,7 @@ var ScreenshotService = new Lang.Class({ y + height <= global.screen_height; }, - _onScreenshotComplete(obj, result, area, filenameUsed, flash, invocation) { + _onScreenshotComplete(result, area, filenameUsed, flash, invocation) { if (result) { if (flash) { let flashspot = new Flashspot(area); @@ -157,9 +157,15 @@ var ScreenshotService = new Lang.Class({ if (!screenshot) return; screenshot.screenshot_area (x, y, width, height, filename, - (obj, result, area, filenameUsed) => { - this._onScreenshotComplete(obj, result, area, filenameUsed, - flash, invocation); + (o, res) => { + try { + let [result, area, filenameUsed] = + screenshot.screenshot_area_finish(res); + this._onScreenshotComplete(result, area, filenameUsed, + flash, invocation); + } catch (e) { + invocation.return_gerror (e); + } }); }, @@ -169,9 +175,15 @@ var ScreenshotService = new Lang.Class({ if (!screenshot) return; screenshot.screenshot_window (include_frame, include_cursor, filename, - (obj, result, area, filenameUsed) => { - this._onScreenshotComplete(obj, result, area, filenameUsed, - flash, invocation); + (o, res) => { + try { + let [result, area, filenameUsed] = + screenshot.screenshot_window_finish(res); + this._onScreenshotComplete(result, area, filenameUsed, + flash, invocation); + } catch (e) { + invocation.return_gerror (e); + } }); }, @@ -181,9 +193,15 @@ var ScreenshotService = new Lang.Class({ if (!screenshot) return; screenshot.screenshot(include_cursor, filename, - (obj, result, area, filenameUsed) => { - this._onScreenshotComplete(obj, result, area, filenameUsed, - flash, invocation); + (o, res) => { + try { + let [result, area, filenameUsed] = + screenshot.screenshot_finish(res); + this._onScreenshotComplete(result, area, filenameUsed, + flash, invocation); + } catch (e) { + invocation.return_gerror (e); + } }); }, diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c index e0b765d53..f26ff64b5 100644 --- a/src/shell-screenshot.c +++ b/src/shell-screenshot.c @@ -38,8 +38,6 @@ struct _ShellScreenshotPrivate gboolean include_cursor; gboolean include_frame; - - ShellScreenshotCallback callback; }; G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT); @@ -59,17 +57,15 @@ shell_screenshot_init (ShellScreenshot *screenshot) static void on_screenshot_written (GObject *source, - GAsyncResult *result, + GAsyncResult *task, gpointer user_data) { ShellScreenshot *screenshot = SHELL_SCREENSHOT (source); ShellScreenshotPrivate *priv = screenshot->priv; + GTask *result = user_data; - if (priv->callback) - priv->callback (screenshot, - g_task_propagate_boolean (G_TASK (result), NULL), - &priv->screenshot_area, - priv->filename_used); + g_task_return_boolean (result, g_task_propagate_boolean (G_TASK (task), NULL)); + g_object_unref (result); g_clear_pointer (&priv->image, cairo_surface_destroy); g_clear_pointer (&priv->filename, g_free); @@ -313,14 +309,15 @@ _draw_cursor_image (MetaCursorTracker *tracker, static void grab_screenshot (ClutterActor *stage, - ShellScreenshot *screenshot) + GTask *result) { MetaDisplay *display; MetaCursorTracker *tracker; int width, height; - GTask *result; GSettings *settings; + ShellScreenshot *screenshot = g_task_get_source_object (result); ShellScreenshotPrivate *priv = screenshot->priv; + GTask *task; display = shell_global_get_display (priv->global); meta_display_get_size (display, &width, &height); @@ -380,19 +377,20 @@ grab_screenshot (ClutterActor *stage, } g_object_unref (settings); - g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot); + g_signal_handlers_disconnect_by_func (stage, grab_screenshot, result); - result = g_task_new (screenshot, NULL, on_screenshot_written, NULL); - g_task_run_in_thread (result, write_screenshot_thread); - g_object_unref (result); + task = g_task_new (screenshot, NULL, on_screenshot_written, result); + g_task_run_in_thread (task, write_screenshot_thread); + g_object_unref (task); } static void grab_area_screenshot (ClutterActor *stage, - ShellScreenshot *screenshot) + GTask *result) { - GTask *result; + ShellScreenshot *screenshot = g_task_get_source_object (result); ShellScreenshotPrivate *priv = screenshot->priv; + GTask *task; do_grab_screenshot (screenshot, CLUTTER_STAGE (stage), @@ -401,18 +399,19 @@ grab_area_screenshot (ClutterActor *stage, priv->screenshot_area.width, priv->screenshot_area.height); - g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot); - result = g_task_new (screenshot, NULL, on_screenshot_written, NULL); - g_task_run_in_thread (result, write_screenshot_thread); - g_object_unref (result); + g_signal_handlers_disconnect_by_func (stage, grab_area_screenshot, result); + task = g_task_new (screenshot, NULL, on_screenshot_written, result); + g_task_run_in_thread (task, write_screenshot_thread); + g_object_unref (task); } static void grab_window_screenshot (ClutterActor *stage, - ShellScreenshot *screenshot) + GTask *result) { + ShellScreenshot *screenshot = g_task_get_source_object (result); ShellScreenshotPrivate *priv = screenshot->priv; - GTask *result; + GTask *task; GSettings *settings; MetaDisplay *display = shell_global_get_display (priv->global); MetaCursorTracker *tracker; @@ -451,10 +450,31 @@ grab_window_screenshot (ClutterActor *stage, } g_object_unref (settings); - g_signal_handlers_disconnect_by_func (stage, (void *)grab_window_screenshot, (gpointer)screenshot); - result = g_task_new (screenshot, NULL, on_screenshot_written, NULL); - g_task_run_in_thread (result, write_screenshot_thread); - g_object_unref (result); + g_signal_handlers_disconnect_by_func (stage, grab_window_screenshot, result); + task = g_task_new (screenshot, NULL, on_screenshot_written, result); + g_task_run_in_thread (task, write_screenshot_thread); + g_object_unref (task); +} + +static gboolean +finish_screenshot (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error) +{ + ShellScreenshotPrivate *priv = screenshot->priv; + + if (!g_task_propagate_boolean (G_TASK (result), error)) + return FALSE; + + if (area) + *area = &priv->screenshot_area; + + if (filename_used) + *filename_used = priv->filename_used; + + return TRUE; } /** @@ -464,39 +484,79 @@ grab_window_screenshot (ClutterActor *stage, * @filename: The filename for the screenshot * @callback: (scope async): function to call returning success or failure * of the async grabbing + * @user_data: the data to pass to callback function * * Takes a screenshot of the whole screen * in @filename as png image. * */ void -shell_screenshot_screenshot (ShellScreenshot *screenshot, - gboolean include_cursor, - const char *filename, - ShellScreenshotCallback callback) +shell_screenshot_screenshot (ShellScreenshot *screenshot, + gboolean include_cursor, + const char *filename, + GAsyncReadyCallback callback, + gpointer user_data) { ClutterActor *stage; ShellScreenshotPrivate *priv = screenshot->priv; + GTask *result; if (priv->filename != NULL) { if (callback) - callback (screenshot, FALSE, NULL, ""); + g_task_report_new_error (screenshot, + callback, + user_data, + shell_screenshot_screenshot, + G_IO_ERROR, + G_IO_ERROR_PENDING, + "Only one screenshot operation at a time " + "is permitted"); return; } + result = g_task_new (screenshot, NULL, callback, user_data); + g_task_set_source_tag (result, shell_screenshot_screenshot); + priv->filename = g_strdup (filename); - priv->callback = callback; priv->include_cursor = include_cursor; stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); meta_disable_unredirect_for_display (shell_global_get_display (priv->global)); - g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)screenshot); + g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), result); clutter_actor_queue_redraw (stage); } +/** + * shell_screenshot_screenshot_finish: + * @screenshot: the #ShellScreenshot + * @result: the #GAsyncResult that was provided to the callback + * @area: (out) (transfer none): the area that was grabbed in screen coordinates + * @filename_used: (out) (transfer none): the name of the file the screenshot + * was written to + * @error: #GError for error reporting + * + * Finish the asynchronous operation started by shell_screenshot_screenshot() + * and obtain its result. + * + * Returns: whether the operation was successful + * + */ +gboolean +shell_screenshot_screenshot_finish (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error) +{ + g_return_val_if_fail (g_async_result_is_tagged (result, + shell_screenshot_screenshot), + FALSE); + return finish_screenshot (screenshot, result, area, filename_used, error); +} + /** * shell_screenshot_screenshot_area: * @screenshot: the #ShellScreenshot @@ -507,45 +567,85 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot, * @filename: The filename for the screenshot * @callback: (scope async): function to call returning success or failure * of the async grabbing + * @user_data: the data to pass to callback function * * Takes a screenshot of the passed in area and saves it * in @filename as png image. * */ void -shell_screenshot_screenshot_area (ShellScreenshot *screenshot, - int x, - int y, - int width, - int height, - const char *filename, - ShellScreenshotCallback callback) +shell_screenshot_screenshot_area (ShellScreenshot *screenshot, + int x, + int y, + int width, + int height, + const char *filename, + GAsyncReadyCallback callback, + gpointer user_data) { ClutterActor *stage; ShellScreenshotPrivate *priv = screenshot->priv; + GTask *result; if (priv->filename != NULL) { if (callback) - callback (screenshot, FALSE, NULL, ""); + g_task_report_new_error (screenshot, + callback, + NULL, + shell_screenshot_screenshot_area, + G_IO_ERROR, + G_IO_ERROR_PENDING, + "Only one screenshot operation at a time " + "is permitted"); return; } + result = g_task_new (screenshot, NULL, callback, user_data); + g_task_set_source_tag (result, shell_screenshot_screenshot_area); + priv->filename = g_strdup (filename); priv->screenshot_area.x = x; priv->screenshot_area.y = y; priv->screenshot_area.width = width; priv->screenshot_area.height = height; - priv->callback = callback; stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ())); - g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)screenshot); + g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), result); clutter_actor_queue_redraw (stage); } +/** + * shell_screenshot_screenshot_area_finish: + * @screenshot: the #ShellScreenshot + * @result: the #GAsyncResult that was provided to the callback + * @area: (out) (transfer none): the area that was grabbed in screen coordinates + * @filename_used: (out) (transfer none): the name of the file the screenshot + * was written to + * @error: #GError for error reporting + * + * Finish the asynchronous operation started by shell_screenshot_screenshot_area() + * and obtain its result. + * + * Returns: whether the operation was successful + * + */ +gboolean +shell_screenshot_screenshot_area_finish (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error) +{ + g_return_val_if_fail (g_async_result_is_tagged (result, + shell_screenshot_screenshot_area), + FALSE); + return finish_screenshot (screenshot, result, area, filename_used, error); +} + /** * shell_screenshot_screenshot_window: * @screenshot: the #ShellScreenshot @@ -554,31 +654,43 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot, * @filename: The filename for the screenshot * @callback: (scope async): function to call returning success or failure * of the async grabbing + * @user_data: the data to pass to callback function * * Takes a screenshot of the focused window (optionally omitting the frame) * in @filename as png image. * */ void -shell_screenshot_screenshot_window (ShellScreenshot *screenshot, - gboolean include_frame, - gboolean include_cursor, - const char *filename, - ShellScreenshotCallback callback) +shell_screenshot_screenshot_window (ShellScreenshot *screenshot, + gboolean include_frame, + gboolean include_cursor, + const char *filename, + GAsyncReadyCallback callback, + gpointer user_data) { ShellScreenshotPrivate *priv = screenshot->priv; MetaDisplay *display = shell_global_get_display (priv->global); ClutterActor *stage; MetaWindow *window = meta_display_get_focus_window (display); + GTask *result; if (priv->filename != NULL || !window) { if (callback) - callback (screenshot, FALSE, NULL, ""); + g_task_report_new_error (screenshot, + callback, + NULL, + shell_screenshot_screenshot_window, + G_IO_ERROR, + G_IO_ERROR_PENDING, + "Only one screenshot operation at a time " + "is permitted"); return; } + result = g_task_new (screenshot, NULL, callback, user_data); + g_task_set_source_tag (result, shell_screenshot_screenshot_window); + priv->filename = g_strdup (filename); - priv->callback = callback; priv->include_frame = include_frame; priv->include_cursor = include_cursor; @@ -586,11 +698,39 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ())); - g_signal_connect_after (stage, "paint", G_CALLBACK (grab_window_screenshot), (gpointer)screenshot); + g_signal_connect_after (stage, "paint", G_CALLBACK (grab_window_screenshot), result); clutter_actor_queue_redraw (stage); } +/** + * shell_screenshot_screenshot_window_finish: + * @screenshot: the #ShellScreenshot + * @result: the #GAsyncResult that was provided to the callback + * @area: (out) (transfer none): the area that was grabbed in screen coordinates + * @filename_used: (out) (transfer none): the name of the file the screenshot + * was written to + * @error: #GError for error reporting + * + * Finish the asynchronous operation started by shell_screenshot_screenshot_window() + * and obtain its result. + * + * Returns: whether the operation was successful + * + */ +gboolean +shell_screenshot_screenshot_window_finish (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error) +{ + g_return_val_if_fail (g_async_result_is_tagged (result, + shell_screenshot_screenshot_window), + FALSE); + return finish_screenshot (screenshot, result, area, filename_used, error); +} + ShellScreenshot * shell_screenshot_new (void) { diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h index df00568f7..61178e2ec 100644 --- a/src/shell-screenshot.h +++ b/src/shell-screenshot.h @@ -16,28 +16,41 @@ G_DECLARE_FINAL_TYPE (ShellScreenshot, shell_screenshot, ShellScreenshot *shell_screenshot_new (void); -typedef void (*ShellScreenshotCallback) (ShellScreenshot *screenshot, - gboolean success, - cairo_rectangle_int_t *screenshot_area, - const gchar *filename_used); +void shell_screenshot_screenshot_area (ShellScreenshot *screenshot, + int x, + int y, + int width, + int height, + const char *filename, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean shell_screenshot_screenshot_area_finish (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error); -void shell_screenshot_screenshot_area (ShellScreenshot *screenshot, - int x, - int y, - int width, - int height, - const char *filename, - ShellScreenshotCallback callback); +void shell_screenshot_screenshot_window (ShellScreenshot *screenshot, + gboolean include_frame, + gboolean include_cursor, + const char *filename, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean shell_screenshot_screenshot_window_finish (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error); -void shell_screenshot_screenshot_window (ShellScreenshot *screenshot, - gboolean include_frame, - gboolean include_cursor, - const char *filename, - ShellScreenshotCallback callback); - -void shell_screenshot_screenshot (ShellScreenshot *screenshot, - gboolean include_cursor, - const char *filename, - ShellScreenshotCallback callback); +void shell_screenshot_screenshot (ShellScreenshot *screenshot, + gboolean include_cursor, + const char *filename, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean shell_screenshot_screenshot_finish (ShellScreenshot *screenshot, + GAsyncResult *result, + cairo_rectangle_int_t **area, + const char **filename_used, + GError **error); #endif /* ___SHELL_SCREENSHOT_H__ */